﻿# -- Abil_m.py
"""
    Copyright 2013 J. Kent Harbaugh

    This file is part of Raddel.

    Raddel is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Raddel is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Raddel.  If not, see <http://www.gnu.org/licenses/>.
"""



class Abils_t:
    def AbilLabels(Self):
        return ('Str','Int','Wis','Dex','Con','Cha')
    def Cha(Self):
        return Self._Cha
    def Char(Self):
        return Self._Char
    def Com(Self):
        if hasattr(Self,'_Com'):
            return Self._Com
        else:
            raise NameError('Abils_t.Com: Comeliness is not being used')
    def Con(Self):
        return Self._Con
    def Dex(Self):
        return Self._Dex
    def Int(Self):
        return Self._Int
    def Gener(Self):
        die=Self.Char().Cmpgn().Dice_t('d6')
        die3=Self.Char().Cmpgn().Dice_t('3d6')
        meth=Self.Char().Cmpgn().Opt().AbilGenerMeth()
        numAbil=len(Self.AbilLabels())
        if meth==0:
            rolls=[]
            for idx in range(numAbil):
                rolls.append(die3())
            scores=rolls
        elif meth==1:
            rolls=[]
            for idx in range(numAbil):
                roll=[die(),die(),die(),die()]
                rolls.append(sum(roll)-min(roll))
            rolls.sort()
            rolls.reverse()
            scores=Self.chooseOrder(rolls)
        elif meth==2:
            rolls=[]
            for idx in range(numAbil):
                rolls.append(die3())
                rolls.append(die3())
            rolls.sort()
            rolls.reverse()
            rolls=rolls[0:numAbil]
            scores=Self.chooseOrder(rolls)
        elif meth==3:
            scores=[]
            for idx in range(numAbil):
                rolls=[]
                for idx2 in range(6):
                    rolls.append(die3())
                scores.append(max(rolls))
        elif meth==4:
            rollSets=[]
            opts=[]
            for idx in range(12):
                rolls=[]
                opt=''
                for label in Self.AbilLabels():
                    roll=die3()
                    rolls.append(roll)
                    opt+=label+':'+str(roll)+' '
                rollSets.append(rolls)
                opts.append(opt)
            scores=Self.chooseSet(rollSets,opts)
        else:
            raise ValueError('Abils_t.Gener: AbilGenerMeth==\''+str(meth)+'\'')
        for (idx,label) in zip(range(numAbil),Self.AbilLabels()):
            getattr(Self,'_'+label).Set(scores[idx])
        if hasattr(Self,'_Com'):
            Self.generCom()
    def Str(Self):
        return Self._Str
    def Wis(Self):
        return Self._Wis
    def __init__(Self,Char):
        Self._Char=Char
        for label in Self.AbilLabels():
            eval('Self._'+label+'='+label+'_t(Self.Char())')
        if Self._Char.Cmpgn().Opt().UseCom():
            Self._Com=Com_t(Self.Char())
    def chooseOrder(Self,Rolls):
        scores=[]
        if Self.Char().IsPlayr():
            opts=[]
            for roll in Rolls:
                opts.append(str(roll))
            for label in Self.AbilLabels():
                opt=Com_p.TxtIo_m.GetOpt(opts,label+'? ')
                scores.append(Rolls[opt])
                del Rolls[opt]
                del opts[opt]
        else:
            random.shuffle(rolls)
            scores=rolls
        return scores
    def chooseSet(Self,RollSets,Opts):
        if Self.Char().IsPlayr():
            opt=GetOpt(opts,'Set? ')
            scores=RollSets[opt]
        else:
            scores=random.choice(RollSets)
        return scores
    def generCom(Self):
        die=Self.Char().Cmpgn().Dice_t('d6')
        die3=Self.Char().Cmpgn().Dice_t('3d6')
        meth=Self.Char().Cmpgn().Opt().ComGenerMethod()
        if meth==0:
            score=die3()
        elif meth==1:
            roll=[die(),die(),die(),die()]
            score=sum(roll)-min(roll)
        elif meth==3:
            rolls=[]
            for idx in range(6):
                rolls.append(die3())
            score=max(rolls)
        else:
            raise ValueError('Abils_m.GenerCom: ComGenerMeth==\''+str(meth)+
                '\'')
        temp=Self.Char().Cmpgn().Temp()
        if not hasattr(temp,'_ChaComModTable'):
            if Self.Char().Cmpgn().Opt().BeCont():
                temp._ChaComModTable=Com_p.Math_m.Interp_t(
                    [(3,-5),(4.5,-3),(7,-1),(10.5,0),(14,1),(16.5,2),
                    (18,3)],(-5,5))
            else:
                temp._ChaComModTable=Com_p.Math_m.Table_t(
                    [(3,-5),(5,-3),(8,-1),(12,0),(15,1),(17,2),(18,3)],5)
        score+=temp._ChaComModTable(Self._Cha)
        Self._Com.Set(score)



class Abil_t:
    def Char(Self):
        return Self._Char
    def Label(Self):
        return Self._Label
    def Score(Self):
        return Self._Score
    def Set(Self,Score):
        Self._Score=Score
    def String(Self):
        score=Self.Score()
        base=int(score)
        exp=round((score-base)*100)
        s=str(base)
        if exp==100:
            s+='/00'
        elif exp:
            s+='/'+str(exp)
        return s
    def __call__(Self):
        return Self.Score()
    def __init__(Self,Char,Label,Score=None):
        Self._Char=Char
        Self._Label=Label
        Self.Set(Score)
    def __str__(Self):
        return Self.String()



class Cha_t(Abil_t):
    def LoyaltyBase(Self):
        return Self.Char().Cmpgn().Temp()._LoyaltyBaseTable(Self.Score())
    def MaxNumHench(Self):
        return Self.Char().Cmpgn().Temp()._MaxNumHenchTable(Self.Score())
    def ReactMod(Self):
        return Self.Char().Cmpgn().Temp()._ReactModTable(Self.Score())
    def __init__(Self,Char,Score=None):
        Abil_t.__init__(Self,Char,'Cha',Score)
        temp=Self.Char().Cmpgn().Temp()
        if Self.Char().Cmpgn().Opt().BeCont():
            if not hasattr(temp,'_LoyaltyBaseTable'):
                temp._LoyaltyBaseTable=Com_p.Math_m.Interp_t(
                    [(3,-30),(4,-25),(5,-20),(6,-15),(7,-10),(8,-5),(11,0),
                    (14,5),(15,15),(16,20),(17,30),(18,40),(19,50),(20,60),
                    (21,70),(22,80),(23,90),(24.5,100)])
            if not hasattr(temp,'_MaxNumHenchTable'):
                temp._MaxNumHenchTable=Com_p.Math_m.Interp_t(
                    [(3.5,1),(5.5,2),(7.5,3),(10,4),(12.5,5),(14,6),
                    (15,7),(16,8),(17,10),(18,15),(19,20),(20,25),(21,30),
                    (22,35),(23,40),(24,45),(25,50)])
            if not hasattr(temp,'_ReactModTable'):
                temp._ReactModTable=Com_p.Math_m.Interp_t(
                    [(3,-25),(4,-20),(5,-15),(6,-10),(7,-5),(10,0),(13,5)
                    (14,10),(15,15),(16,25),(17,30),(18,35),(19,40),(20,45),
                    (21,50),(22,55),(23,60),(24,65),(25,70)])
        else:
            if not hasattr(temp,'_LoyaltyBaseTable'):
                temp._LoyaltyBaseTable=Com_p.Math_m.Table_t(
                    [(3,-30),(4,-25),(5,-20),(6,-15),(7,-10),(8,-5),(13,0),
                    (14,5),(15,15),(16,20),(17,30),(18,40),(19,50),(20,60),
                    (21,70),(22,80),(23,90)],100)
            if not hasattr(temp,'_MaxNumHenchTable'):
                temp._MaxNumHenchTable=Com_p.Math_m.Table_t(
                    [(4,1),(6,2),(8,3),(11,4),(13,5),(14,6),(15,7),(16,8),
                    (17,10),(18,15),(19,20),(20,25),(21,30),(22,35),(23,40),
                    (24,45)],50)
            if not hasattr(temp,'_ReactModTable'):
                temp._ReactModTable=Com_p.Math_m.Table_t(
                    [(3,-25),(4,-20),(5,-15),(6,-10),(7,-5),(12,0),(13,5)
                    (14,10),(15,15),(16,25),(17,30),(18,35),(19,40),(20,45),
                    (21,50),(22,55),(23,60),(24,65)],70)



class Com_t(Abil_t):
    def __init__(Self,Char,Score=None):
        Abil_t.__init__(Self,Char,'Com',Score)



class Con_t(Abil_t):
    def FghtrHitPtMod(Self):
        return Self.Char().Cmpgn().Temp()._FghtrHitPtModTable(Self.Score())
    def HitPtMod(Self):
        return Self.Char().Cmpgn().Temp()._HitPtModTable(Self.Score())
    def MinHitDieRoll(Self):
        return Self.Char().Cmpgn().Temp()._MinHitDieRollTable(Self.Score())
    def RegenTurnsPerHitPt(Self):
        return Self.Char().Cmpgn().Temp()._RegenTurnsPerHitPt(Self.Score())
    def ResSurvPerc(Self):
        return Self.Char().Cmpgn().Temp()._ResSurvPercTable(Self.Score())
    def SysShockSurvPerc(Self):
        return Self.Char().Cmpgn().Temp()._SysShockSurvPercTable(
            Self.Score())
    def __init__(Self,Char,Score=None):
        Abil_t.__init__(Self,Char,'Con',Score)
        temp=Self.Char().Cmpgn().Temp()
        if Self.Char().Cmpgn().Opt().BeCont():
            if not hasattr(temp,'_FghtrHitPtModTable'):
                temp._FghtrHitPtModTable=Com_p.Math_m.Interp_t(
                    [(3,-2),(5,-1),(10.5,0),(15,1),(16,2),(17,3),(18,4),
                    (19.5,5),(22,6),(24.5,7)])
            if not hasattr(temp,'_HitPtModTable'):
                temp._HitPtModTable=Com_p.Math_m.Interp_t(
                    [(3,-2),(5,-1),(10.5,0),(15,1),(16,2)])
            if not hasattr(temp,'_MinHitDieRollTable'):
                temp._MinHitDieRollTable=Com_p.Math_m.Interp_t(
                    [(18,1),(19.5,2),(21.5,3),(24,4)])
            if not hasattr(temp,'_RegenTurnsPerHitPt'):
                temp._RegenTurnsPerHitPt=Com_p.Math_m.Interp_t(
                    [(19,0),(20,6),(21,5),(22,4),(23,3),(24,2),(25,1)])
            if not hasattr(temp,'_ResSurvPercTable'):
                temp._ResSurvPercTable=Com_p.Math_m.Interp_t(
                    [(3,40),(4,45),(5,50),(6,55),(7,60),(8,65),(9,70),
                    (10,75),(11,80),(12,85),(13,90),(14,92),(15,94),(16,96),
                    (17,98),(18,100)])
            if not hasattr(temp,'_SysShockSurvPercTable'):
                temp._SysShockSurvPercTable=Com_p.Math_m.Interp_t(
                    [(3,35),(4,40),(5,45),(6,50),(7,55),(8,60),(9,65),
                    (10,70),(11,75),(12,80),(13,85),(14,88),(15,91),(16,95),
                    (17,97),(18,99),(19,100)])
        else:
            if not hasattr(temp,'_FghtrHitPtModTable'):
                temp._FghtrHitPtModTable=Com_p.Math_m.Table_t(
                    [(3,-2),(6,-1),(14,0),(15,1),(16,2),(17,3),(18,4),
                    (20,5),(23,6)],7)
            if not hasattr(temp,'_HitPtModTable'):
                temp._HitPtModTable=Com_p.Math_m.Table_t(
                    [(3,-2),(6,-1),(14,0),(15,1)],2)
            if not hasattr(temp,'_MinHitDieRollTable'):
                temp._MinHitDieRollTable=Com_p.Math_m.Table_t(
                    [(18,1),(20,2),(22,3)],4)
            if not hasattr(temp,'_RegenTurnsPerHitPt'):
                temp._RegenTurnsPerHitPt=Com_p.Math_m.Table_t(
                    [(19,0),(20,6),(21,5),(22,4),(23,3),(24,2)],1)
            if not hasattr(temp,'_ResSurvPercTable'):
                temp._ResSurvPercTable=Com_p.Math_m.Table_t(
                    [(3,40),(4,45),(5,50),(6,55),(7,60),(8,65),(9,70),
                    (10,75),(11,80),(12,85),(13,90),(14,92),(15,94),(16,96),
                    (17,98)],100)
            if not hasattr(temp,'_SysShockSurvPercTable'):
                temp._SysShockSurvPercTable=Com_p.Math_m.Table_t(
                    [(3,35),(4,40),(5,45),(6,50),(7,55),(8,60),(9,65),
                    (10,70),(11,75),(12,80),(13,85),(14,88),(15,91),(16,95),
                    (17,97),(18,99)],100)



class Dex_t(Abil_t):
    def DefnsMod(Self):
        return Self.Char().Cmpgn().Temp()._DefnsModTable(Self.Score())
    def MisslToHitMod(Self):
        return Self.Char().Cmpgn().Temp()._MisslToHitModTable(Self.Score())
    def ReactMod(Self):
        return Self.MisslToHitMod()
    def __init__(Self,Char,Score=None):
        Abil_t.__init__(Self,Char,'Dex',Score)
        temp=Self.Char().Cmpgn().Temp()
        if Self.Char().Cmpgn().Opt().BeCont():
            if not hasattr(temp,'_DefnsModTable'):
                temp._DefnsModTable=Com_p.Math_m.Interp_t(
                    [(3,4),(4,3),(5,2),(6,1),(10.5,0),(15,-1),(16,-2),
                    (17,-3),(19,-4),(22,-5),(24.5,-6)])
            if not hasattr(temp,'_MisslToHitModTable'):
                temp._MisslToHitModTable=Com_p.Math_m.Interp_t(
                    [(3,-3),(4,-2),(5,-1),(10,0),(16,1),(17,2),(19,3),
                    (22,4),(24.5,5)])
        else:
            if not hasattr(temp,'_DefnsModTable'):
                temp._DefnsModTable=Com_p.Math_m.Table_t(
                    [(3,4),(4,3),(5,2),(6,1),(14,0),(15,-1),(16,-2),(17,-3),
                    (20,-4),(23,-5)],-6)
            if not hasattr(temp,'_MisslToHitModTable'):
                temp._MisslToHitModTable=Com_p.Math_m.Table_t(
                    [(3,-3),(4,-2),(5,-1),(15,0),(16,1),(17,2),(20,3),
                    (23,4)],5)



class Int_t(Abil_t):
    def __init__(Self,Char,Score=None):
        Abil_t.__init__(Self,Char,'Int',Score)



class Str_t(Abil_t):
    def BendBarsPerc(Self):
        return Self.Char().Cmpgn().Temp()._BendBarsPercTable(Self.Score())
    def EncumbMod(Self):
        return Self.Char().Cmpgn().Temp()._EncumbModTable(Self.Score())
    def MeleeDmgMod(Self):
        return Self.Char().Cmpgn().Temp()._MeleeDmgModTable(Self.Score())
    def MeleeToHitMod(Self):
        return Self.Char().Cmpgn().Temp()._MeleeToHitModTable(Self.Score())
    def OpenDoorFrac(Self):
        return Self.Char().Cmpgn().Temp()._OpenDoorFracTable(Self.Score())
    def OpenLockDoorFrac(Self):
        return Self.Char().Cmpgn().Temp()._OpenLockDoorFracTable(
            Self.Score())
    def __init__(Self,Char,Score=None):
        Abil_t.__init__(Self,Char,'Str',Score)
        temp=Self.Char().Cmpgn().Temp()
        if Self.Char().Cmpgn().Opt().BeCont():
            if not hasattr(temp,'_BendBarsPercTable'):
                temp._BendBarsPercTable=Com_p.Math_m.Interp_t(
                    [(5,0),(8.5,1),(10.5,2),(12.5,4),(14.5,7),(16,10),
                    (17,13),(18,16),(18.255,20),(18.63,25),(18.83,30),
                    (18.95,35),(18.999,40),(19,50),(20,60),(21,70),(22,80),
                    (23,90),(24.5,100)])
            if not hasattr(temp,'_EncumbranceModTable'):
                temp._EncumbModTable=Com_p.Math_m.Interp_t(
                    [(3,-350),(4.5,-250),(6.5,-150),(9.5,0),(12.5,100),
                    (14.5,200),(16,350),(17,500),(18,750),(18.255,1000),
                    (18.63,1250),(18.83,1500),(18.95,2000),(18.999,3000),
                    (19,4500),(20,5000),(21,6000),(22,7500),(23,9000),
                    (24,12000),(25,15000)])
            if not hasattr(temp,'_MeleeDmgModTable'):
                temp._MeleeDmgModTable=Com_p.Math_m.Interp_t(
                    [(4,-1),(10.5,0),(16.5,1),(18,2),(18.38,3),(18.83,4),
                    (18.95,5),(18.999,6),(19,7),(20,8),(21,9),(22,10),
                    (23,11),(24,12),(25,14)])
            if not hasattr(temp,'_MeleeToHitModTable'):
                temp._MeleeToHitModTable=Com_p.Math_m.Interp_t(
                    [(3,-3),(4.5,-2),(6.5,-1),(12,0),(17.75,1),(18.75,2),
                    (19.5,3),(21.5,4),(23,5),(24,6),(25,7)])
            if not hasattr(temp,'_OpenDoorFracTable'):
                temp._OpenDoorFracTable=Com_p.Math_m.Interp_t(
                    [(5,1/6),(11.5,2/6),(17.25,3/6),(18.75,4/6),(18.999,5/6),
                    (19.5,7/8),(21,9/10),(22.5,11/12),(24,19/20),(25,23/24)])
            if not hasattr(temp,'_OpenLockDoorFracTable'):
                temp._OpenLockDoorFracTable=Com_p.Math_m.Interp_t(
                    [(10.95,0/6),(18.95,1/6),(18.999,2/6),(19.5,3/6),
                    (21.5,4/6),(23,5/6),(24,7/8),(25,9/10)])
        else:
            if not hasattr(temp,'_BendBarsPercTable'):
                temp._BendBarsPercTable=Com_p.Math_m.Table_t(
                    [(7,0),(9,1),(11,2),(13,4),(15,7),(16,10),(17,13),
                    (18,16),(18.50,20),(18.75,25),(18.90,30),(18.99,35),
                    (18.999,40),(19,50),(20,60),(21,70),(22,80),(23,90)],100)
            if not hasattr(temp,'_EncumbranceModTable'):
                temp._EncumbModTable=Com_p.Math_m.Table_t(
                    [(3,-350),(5,-250),(7,-150),(11,0),(13,100),(15,200),
                    (16,350),(17,500),(18,750),(18.50,1000),(18.75,1250),
                    (18.90,1500),(18.99,2000),(18.999,3000),
                    (19,4500),(20,5000),(21,6000),(22,7500),(23,9000),
                    (24,12000)],15000)
            if not hasattr(temp,'_MeleeDmgModTable'):
                temp._MeleeDmgModTable=Com_p.Math_m.Table_t(
                    [(5,-1),(15,0),(17,1),(18,2),(18.75,3),(18.90,4),
                    (18.99,5),(18.999,6),(19,7),(20,8),(21,9),(22,10),
                    (23,11),(24,12)],14)
            if not hasattr(temp,'_MeleeToHitModTable'):
                temp._MeleeToHitModTable=Com_p.Math_m.Table_t(
                    [(3,-3),(5,-2),(7,-1),(16,0),(18.50,1),(18.99,2),(20,3),
                    (22,4),(23,5),(24,6)],7)
            if not hasattr(temp,'_OpenDoorFracTable'):
                temp._OpenDoorFracTable=Com_p.Math_m.Table_t(
                    [(7,1/6),(15,2/6),(18.50,3/6),(18.99,4/6),(18.999,5/6),
                    (20,7/8),(21,9/10),(23,11/12),(24,19/20)],23/24)
            if not hasattr(temp,'_OpenLockDoorFracTable'):
                temp._OpenLockDoorFracTable=Com_p.Math_m.Table_t(
                    [(18.90,0/6),(18.99,1/6),(18.999,2/6),(20,3/6),
                    (22,4/6),(23,5/6),(24,7/8)],9/10)



class Wis_t(Abil_t):
    def MagAttMod(Self):
        return Self.Char().Cmpgn().Temp()._MagAttModTable(Self.Score())
    def __init__(Self,Char,Score=None):
        Abil_t.__init__(Self,Char,'Wis',Score)
        temp=Self.Char().Cmpgn().Temp()
        if Self.Char().Cmpgn().Opt().BeCont():
            if not hasattr(temp,'_MagAttModTable'):
                temp._MagAttModTable=Com_p.Math_m.Interp_t(
                    [(3,-3),(4,-2),(6,-1),(11,0),(15,1),(16,2),(17,3),
                    (18,4)])
        else:
            if not hasattr(temp,'_MagAttModTable'):
                temp._MagAttModTable=Com_p.Math_m.Table_t(
                    [(3,-3),(4,-2),(7,-1),(14,0),(15,1),(16,2),(17,3)],4)



import Com_p
from . import Char_m



# -- Abil_m.py
